use crate::{
    helpers::{count_ttr, count_unread_posts},
    keyboards,
};

use anyhow::{Context, Result};

use mongodb::bson::spec::BinarySubtype;
use mongodb::bson::Binary;
use mongodb::options::FindOneOptions;

use teloxide::payloads::SendMessageSetters;
use teloxide::prelude2::*;

pub async fn random(bot: AutoSend<Bot>, m: Message) -> Result<()> {
    let user_id = m.from().context("get user id NoneError")?.id;
    println!("test 0");
    let user = get_user(user_id).await?;
    let doc_count = count_unread_posts(user.id).await?;
    if doc_count == 0 {
        all_posts_viewed(&bot, user_id).await?;
    } else {
        let user = get_user(user_id).await?;
        println!("test");
        let random_id = gen_random_number(doc_count);
        let user_post = get_user_post(user.id, random_id).await?;
        println!("{:#?}", &user_post);
        println!("test2");
        let post = get_post(user_post.post_id).await?;
        let url = {
            if original_or_real(&user, &user_post) {
                println!("test3");
                post.real_url
            } else {
                user_post
                    /*.original_url()*/
                    .original_url
                    .clone()
            }
        };
        let ttr = count_ttr(post.word_count);
        let mut answer = {
            /*        if let Some(title) = post.title {
                format!("[{}]({})", title, url)
            }
            else {*/
            url
            // }
        };
        println!("{}", answer);
        if let Some(ttr) = ttr {
            answer.push_str(&format!(" {} minutes", ttr))
        };
        println!("{}", answer);
        bot.send_message(user_id, answer)
            .reply_markup(keyboards::standart_keyboard(&user_post.post_id.to_string()))
            //.parse_mode(teloxide::types::ParseMode::MarkdownV2)
            .await?;
    }
    Ok(())
}
use crate::db::connect_to_db;
use futures::stream::StreamExt;
use mongodb::bson::{doc, from_document, Document};
use rand::Rng;
async fn get_post(post_id: Uuid) -> Result<PostRandom> {
    let bin_id = Binary {
        subtype: BinarySubtype::Uuid,
        bytes: post_id.as_bytes().to_vec(),
    };
    let db = connect_to_db().await?;
    let coll = db.collection::<PostRandom>("posts");
    let filter = doc! {
        "id": bin_id
    };
    println!("itest");
    let projection = doc! {
        "real_url": 1,
        "word_count":1,
        "title": 1,
    };
    let options = FindOneOptions::builder().projection(projection).build();
    println!("itest2");
    let res = coll.find_one(filter, options).await?.context("haha")?;
    Ok(res)
}
fn gen_random_number(doc_count: u64) -> u64 {
    let mut rng = rand::thread_rng();
    rng.gen_range(0..=doc_count)
}
async fn all_posts_viewed(bot: &AutoSend<Bot>, user_id: i64) -> Result<()> {
    bot.send_message(user_id, "All unread posts vieved!")
        .await?;
    Ok(())
}
pub async fn get_user(user_id: i64) -> Result<UserRandom> {
    let db = connect_to_db().await?;
    let match_aggr = doc! {
        "$match":{
            "telegram_id": user_id
        }
    };
    let proj_aggr = doc! {
        "$project": {
            "id":1,
            "show_real_url":1
        }
    };
    let pipeline = [match_aggr, proj_aggr];
    let user_coll = db.collection::<UserRandom>("users");
    let res = user_coll
        .aggregate(pipeline, None)
        .await
        .context("test23")?
        .next()
        .await
        .context("get_user NoneError")??;
    Ok(from_document::<UserRandom>(res)?)
}
use mongodb::bson::serde_helpers::uuid_as_binary;
use serde::Deserialize;
use uuid::Uuid;
#[derive(Debug, Deserialize)]
pub struct UserRandom {
    #[serde(with = "uuid_as_binary")]
    pub id: Uuid,
    pub show_real_url: bool,
}
#[derive(Debug, Deserialize)]
pub struct UserPostRandom {
    #[serde(with = "uuid_as_binary")]
    pub post_id: Uuid,
    pub original_url: String,
    pub show_real_url: bool,
}
#[derive(Debug, Deserialize)]
pub struct PostRandom {
    pub real_url: String,
    title: Option<String>,
    word_count: Option<i64>,
}
fn original_or_real(user: &UserRandom, post: &UserPostRandom) -> bool {
    user.show_real_url || post.show_real_url
}
async fn get_user_post(user_id: Uuid, skip_id: u64) -> Result<UserPostRandom> {
    let db = connect_to_db().await?;
    let match_aggr = doc! {
        "$match": {
        "user_id": user_id,
        }
    };
    let proj_aggr = doc! {
        "$project": {
        "original_url":1_i32,
        "show_real_url":1_i32,
        "post_id":1_i32,
        }
    };
    /*let unwind_aggr = doc! {
        "$unwind": "$posts"
    };
    let replace_with_aggr = doc! {
        "$replaceWith": {
            "$mergeObjects":
        [
            {"post_id": 0, "original_url":0, "show_real_url": 0,}, "$posts"
        ]
    }
    };*/
    let skip_aggr = doc! {
        "$skip": skip_id as f64
    };
    let limit_aggr = doc! {
        "$limit": 1_i32
    };
    /*  let unset_aggr = doc! {
        "$unset": "_id"
    };*/
    let pipeline = [
        match_aggr, proj_aggr, //unwind_aggr,
        //replace_with_aggr,
        skip_aggr, limit_aggr,
        //unset_aggr,
    ];
    let user_coll = db.collection::<Document>("userposts");
    let user_random = user_coll
        .aggregate(pipeline, None)
        .await
        .context("test34")?
        .next()
        .await
        .context("get_user_post NoneError")??;
    println!("{:#?}", user_random);
    println!("itest3");
    let res = from_document::<UserPostRandom>(user_random)?;

    Ok(res)
}
